package object

import "fmt"

func newError(format string, a ...interface{}) *Error {
	return &Error{Message: fmt.Sprintf(format, a...)}
}

func GetBuiltinByName(name string) *Builtin {
	for _, def := range Builtins {
		if def.Name == name {
			return def.Builtin
		}
	}
	return nil
}

var Builtins = []struct {
	Name    string
	Builtin *Builtin
}{
	{"len", &Builtin{
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments!")
			}
			switch arg := args[0].(type) {
			case *String:
				return &Integer{Value: int64(len(arg.Value))}
			case *Array:
				return &Integer{Value: int64(len(arg.Elements))}
			}
			return newError("len() not support type %s", args[0].Type())
		},
	}},
	{"puts", &Builtin{
		Fn: func(args ...Object) Object {
			for _, arg := range args {
				fmt.Println(arg.Inspect())
			}
			return nil
		},
	}},
	{"first", &Builtin{
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments!")
			}
			if args[0].Type() != ARRAY_OBJ {
				return newError("argument to `first` must be array!")
			}
			arr := args[0].(*Array)
			if len(arr.Elements) > 0 {
				return arr.Elements[0]
			}
			return nil
		},
	}},
	{"last", &Builtin{
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments!")
			}
			if args[0].Type() != ARRAY_OBJ {
				return newError("argument to `last` must be array!")
			}
			arr := args[0].(*Array)
			length := len(arr.Elements)
			if length > 0 {
				return arr.Elements[length-1]
			}
			return nil
		},
	}},
	{"rest", &Builtin{Fn: func(args ...Object) Object {
		if len(args) != 1 {
			return newError("wrong number of arguments!")
		}
		if args[0].Type() != ARRAY_OBJ {
			return newError("argument to `last` must be array!")
		}
		arr := args[0].(*Array)
		length := len(arr.Elements)
		if length > 0 {
			newElements := make([]Object, length-1, length-1)
			copy(newElements, arr.Elements[1:length])
			return &Array{Elements: newElements}
		}
		return nil
	}}},
	{"push", &Builtin{Fn: func(args ...Object) Object {
		if len(args) != 2 {
			return newError("wrong number of arguments!")
		}
		if args[0].Type() != ARRAY_OBJ {
			return newError("argument to `last` must be array!")
		}
		arr := args[0].(*Array)
		length := len(arr.Elements)

		newElements := make([]Object, length+1, length+1)
		copy(newElements, arr.Elements)
		newElements[length] = args[1]
		return &Array{Elements: newElements}
	}}},
}
